/*
 * Media mother class, basis for DVD and Book classes
 * a media contains its name, edition date, amount of copies
 * and array of copies.
 * author: G. Piraux, M-A. Taupenot
 * version: 1.0.1
 * date: 21/05/2012
 * 
 */

package booksManagement;


import java.io.Serializable;
import java.util.*;

import exceptions.*;

import javax.persistence.*;

import subscribersManagement.Subscriber;

/**
 * @author    user
 */
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="mediatype",discriminatorType=DiscriminatorType.STRING)
@Table(name="medias")
@NamedQuery(name="findAllMedias", query="select m from Media m")
public abstract class Media implements Serializable
{
	/**
   * 
   */
  private static final long serialVersionUID = 1L;
	/**
   * @uml.property  name="id"
   */
	@Id
	protected String isbn_isan;
	

	/**
   * @uml.property  name="title"
   */
	@Column(name="title")
	protected String title;
	/**
   * @uml.property  name="editionDate"
   */
	@Column(name="edition_date")
	protected Calendar editionDate;
	
	//@Transient
	@ManyToMany(targetEntity = Subscriber.class, cascade = CascadeType.ALL)
  @JoinTable(
      name="Reservations",
      joinColumns={@JoinColumn(name="isbn_isan", referencedColumnName="isbn_isan")},
      inverseJoinColumns={@JoinColumn(name="Subscriber_ID", referencedColumnName="number")})
	protected List<Subscriber> reservers;
	/*/**
  * * number of copies of the media in circulation
  * * @uml.property  name="copyAmount"
  * *'/
	* @Column(name="copyAmount")
	* protected int copyAmount=0;
	* /**
  * * Key used to create the copy number
  * * @uml.property  name="copyKey"
  * *'/
	*/
	
	//@Transient
	/**
   * @uml.property  name="nbLentCopies"
   */
	protected int nbLentCopies=0;
	/**
   * @uml.property  name="copies"
   */
	//@Transient
	@OneToMany(mappedBy = "media")
	protected List<Copy> copies;
	
  //The simpliest constructor with no argument  	
  public Media(){
    copies = new ArrayList<Copy>();
    reservers = new LinkedList<Subscriber>();
  }
   
	/**
	 * light constructor with only name and edition date
	 * 
	 * @param title
	 * @throws BadParametersException
	 */
	public Media(String title, Calendar editionDate)throws BadParametersException{
		this();
		this.setTitle(title);
		this.setEditionDate(editionDate);
		
	}
	/**
	 * constructor that handle the creation of a certain amount
	 * of copies
	 * 
	 * @param title
	 * @param editionDate
	 * @param copyAmount
	 * @throws BadParametersException
	 */
	public Media(String title, Calendar editionDate, int copyAmount)throws BadParametersException{
		this(title, editionDate);
		if (copyAmount<1)
			throw new BadParametersException("wrong copy amount");
		else{
			//this.copyAmount=copyAmount;
			for (int i=0; i<copyAmount;i++){
				this.copies.add(new Copy(this));
			}
		}	
	}
	
	/**
   * @return
   * @uml.property  name="id"
   */
	public String getIsbn_isan(){
		return isbn_isan;
	}
	
	/**
   * @param  Id
   * @uml.property  name="id"
   */
	public void setIsbn_isan(String isbn_isan){
		this.isbn_isan=isbn_isan;
	}
	/**
   * @return
   * @uml.property  name="title"
   */
	public String getTitle(){
		return this.title;
	}
	
	/**
   * @param title
   * @throws BadParametersException
   * @uml.property  name="title"
   */
	public void setTitle(String title) throws BadParametersException{
		if (title==null) throw new BadParametersException();
		this.title=title;
	}
	
	/**
   * @return
   * @uml.property  name="editionDate"
   */
	public Calendar getEditionDate(){
		return this.editionDate;
	}
	
	/**
   * @param editionDate
   * @throws BadParametersException
   * @uml.property  name="editionDate"
   */
	public void setEditionDate(Calendar editionDate) throws BadParametersException{
		if (editionDate==null) throw new NullPointerException("wrong edition date");
		this.editionDate=editionDate;
	}
	
	/*/**
  * * @return
  * * @uml.property  name="copyAmount"
  * *'/
	*public int getCopyAmount(){
	*	return this.copyAmount;
	*}
	*
	*'/**
  * * @param copyAmount
  * * @uml.property  name="copyAmount"
  * *'/
	*public void setCopyAmount(int copyAmount){
	*	this.copyAmount=copyAmount;
	*}
	*/
	
	/**
   * @return
   * @uml.property  name="nbLentCopies"
   */
	public int getNbLentCopies(){
		return nbLentCopies;
	}
	
	/**
   * @param  nbLentCopies
   * @uml.property  name="nbLentCopies"
   */
	public void setNbLentCopies(int nbLentCopies){
		if (nbLentCopies < 0 || nbLentCopies > copies.size())
				throw new IndexOutOfBoundsException("wrong value of nbLentCopies");
		this.nbLentCopies=nbLentCopies;
	}
	
	public boolean noLentCopy(){
		if (nbLentCopies==0)
			return true;
		else
			return false;
	}
	
	public boolean allCopiesLent(){
		if (nbLentCopies==copies.size())
			return true;
		else
			return false;
	}
	/**
   * @return
   * @uml.property  name="copies"
   */
	public List<Copy> getCopies(){
		return copies;
	}
	
	/**
   * @param copies
   * @throws BadParametersException
   * @uml.property  name="copies"
   */
	public void setCopies(List<Copy> copies)throws BadParametersException{
		if (copies==null) throw new BadParametersException("no copies specified");
		this.copies=copies;
	}
	/**
	 * appends a unique new Copy to the end of the list copies
	 * @throws BadParametersException
	 */
	public Copy addCopy() throws BadParametersException{
		//this.copyAmount++;
		Copy c = new Copy(this);
		copies.add(c);
		
		return c;
	}
	
	/**
	 * Remove the copy from the array of copies
	 * @param c
	 * @return
	 * @throws LentBookException
	 */
	public boolean removeCopy(Copy c)throws LentBookException{
		if (c.isLent())
			throw new LentBookException("Copy is lent");
		return copies.remove(c);
	}
	
	

	public List<Subscriber> getReservers()
  {
  	return reservers;
  }

	public void setReservers(List<Subscriber> subscribers)
  {
		if (subscribers==null)
			throw new NullPointerException("subscribers is null");
  	this.reservers = subscribers;
  }
	
	public void addReserver(Subscriber s) throws TooManyReservationsException{
		if (s==null)
			throw new NullPointerException("null value of reserver");
		if (reservers.size()<copies.size())
			this.reservers.add(s);
		else
			throw new TooManyReservationsException("reservation limit for this media reached");
	}
	
	public boolean removeSubscriber(Subscriber s){
		return reservers.remove(s);
	}
	
	
	@Override
	public String toString() {
		return this.title;
	}

}
